#include <iostream>
#include "sock_app.h"
#include "tcp_server.h"
#include <iostream>
#include "server_node.h"
#include "net_io_manager.h"

static int setSocketNonBlock(int sock_fd){
    int old_opt = fcntl(sock_fd, F_GETFL);
    int new_opt = old_opt | O_NONBLOCK;
    fcntl(sock_fd, F_SETFL, new_opt);
    return old_opt;
}

CTCPServer::CTCPServer()
{
    m_fd_epoll = -1;
    m_fd_listen = -1;
    m_quit_flag = true;
    m_io_mgr = new CNetIOManager();
}

CTCPServer::~CTCPServer(){
    if (m_fd_epoll != -1){
        close(m_fd_epoll);
        m_fd_epoll = -1;
    }

    if (m_fd_listen != -1){
        close(m_fd_listen);
        m_fd_listen = -1;
    }
    m_quit_flag = true;

    if (m_io_mgr){
        m_io_mgr->stop();
        delete m_io_mgr;
        m_io_mgr = NULL;
    }
}

void CTCPServer::start()
{
    if (m_fd_epoll != -1)
    {
        std::cerr << "epoll fd does already exist." << std::endl;
        return;
    }
    m_quit_flag = false;

    m_io_mgr->start();

    m_fd_epoll = epoll_create1(EPOLL_CLOEXEC);
    // try listen.
    m_fd_listen = socket(PF_INET, SOCK_STREAM, 0);
    if (-1 == m_fd_listen){
        perror("socket()");
        close(m_fd_epoll);
        return;
    }
    printf("创建listen用socket成功！\n");
    setSocketNonBlock(m_fd_listen);
    sockaddr_in server_host;
    memset(&server_host, 0, sizeof(server_host));
    server_host.sin_family = PF_INET;
    unsigned short port = 3001;
    server_host.sin_port = htons(port); //Our server will listen on 0.0.0.0:3389.
    server_host.sin_addr.s_addr = INADDR_ANY;
    if (-1 == bind(m_fd_listen, (struct sockaddr*)&server_host, sizeof(struct sockaddr))){
        perror("bind()");
        close(m_fd_listen);
        close(m_fd_epoll);
        return;
    }
    printf("Bind 0.0.0.0:%d OK!\n",port);
    if (-1 == listen(m_fd_listen, 128)){
        perror("listen()");
        close(m_fd_listen);
        close(m_fd_epoll);
        return;
    }

    // 将listen socket加入到epoll监听列表，当有新连接到来时将被通知。
    epoll_event e;
    e.events = EPOLLIN | EPOLLET;
    e.data.fd = m_fd_listen;
    epoll_ctl(m_fd_epoll, EPOLL_CTL_ADD, m_fd_listen, &e);

    m_IOThread.create(&IOThreadFunction, this);
}

void CTCPServer::epoll_update(int epoll_opcode, int fd, epoll_event* ev)
{
    //@TODO: 暂不确定是否需要用整个互斥体保护。
    std::lock_guard<std::recursive_mutex> l(m_mutex_epoll_fd);
    epoll_ctl(m_fd_epoll, epoll_opcode, fd, ev);
}

void CTCPServer::stop()
{
    if (m_io_mgr){
        m_io_mgr->stop();
        delete m_io_mgr;
        m_io_mgr = NULL;
    }

    m_quit_flag = true;
    if (m_fd_epoll != -1)
    {
        close(m_fd_epoll);
        m_fd_epoll = -1;
    }

}

void *CTCPServer::IOThreadFunction(void *lp)
{
    CTCPServer* pTcpServer = (CTCPServer*)(lp);
    pTcpServer->IOThreadImpl();
    return NULL;
}

void CTCPServer::close_and_remove_from_list(int fd){
    std::unordered_map<int, std::shared_ptr<CServerNode>>::const_iterator it;
    it = m_connections.find(fd);
    if (it != m_connections.end()){
        it->second->onSocketClosed();
        m_connections.erase(it);
    }
}

void CTCPServer::IOThreadImpl()
{
    struct epoll_event ev[16];
    while(!m_quit_flag)
    {
        //std::vector<struct epoll_event> revents;
        //返回的事件集合在ev数组中，数组中实际存放的成员个数是函数的返回值。返回0表示已经超时。
        int event_cnt = epoll_wait(m_fd_epoll, ev, 16, 5000);
        //printf("epoll event count:%d\n", nEvent);
        if (event_cnt <= 0)
            continue;
        for (int i = 0; i < event_cnt; ++i)
        {
            if (ev[i].data.fd == m_fd_listen)
            {
                // ACCEPT连接
                sockaddr_in remote_addr;
                socklen_t sockaddr_len = sizeof(sockaddr_in);
                int new_fd = accept(m_fd_listen, (sockaddr*)&remote_addr, &sockaddr_len);
                if (new_fd < 0){
                    perror("accept()");
                    continue;
                }
                printf("Accepted a new socket %d\n", new_fd);

                setSocketNonBlock(new_fd);
                std::shared_ptr<CServerNode> node(new CServerNode(new_fd, m_fd_epoll, m_io_mgr));
                if (m_connections.find(new_fd) != m_connections.end()){
                    printf("Error!socket %d Already exist in connection list.\n", new_fd);
                    close_and_remove_from_list(new_fd);
                    return;
                }
                
                m_connections[new_fd] = node;
                node->onAccept(remote_addr);
            }
            else
            {
                if(ev[i].events & EPOLLIN)
                {
                    // 有数据到了，读完输入缓冲区中所有数据。
                    int sock_fd = ev[i].data.fd;
                    std::shared_ptr<CServerNode> node;
                    {
                        std::lock_guard<std::recursive_mutex> l(m_mutex_conn);
                        if (m_connections.find(sock_fd) == m_connections.end())
                            continue;
                        node = m_connections[sock_fd];
                        if (!node){
                            printf("EPOLLIN | connections for fd %d is not valid.\n",sock_fd);
                            continue;
                        }
                    }

                    std::string data;
                    char tmp_buf[4096];
                    int n = 0;
                    
                    while (1) {
                        n = read(sock_fd, tmp_buf, sizeof(tmp_buf));
                        if (n > 0)
                        {
                            data.append(tmp_buf, n);
                        }
                        else if (n == 0)
                        {
                            // 对方关闭了连接。
                            // 或许已经接收数据到data变量，但是我这里为简单起见直接丢弃它。
                            printf("对方关闭了连接。\n");
                            close_and_remove_from_list(sock_fd);
                            break;
                        }
                        else
                        {
                            if (errno == EAGAIN || errno == EWOULDBLOCK)
                            {
                                if (!data.empty())
                                    node->onDataRecved(data);
                                break;
                            }
                            else if (errno == EINTR)
                            {
                                printf("recv error EINTR\n");
                                continue;
                            }
                            else
                            {
                                printf("socket recv data error: %d\n", errno);
                                node->onSocketError(errno);
                                close_and_remove_from_list(sock_fd);
                                break;
                            }
                        }
                    }
                    // 数据接收完毕，等待下一个数据到来事件。
                }
                else if(ev[i].events & EPOLLOUT)
                {
                    // 检查需要发送的数据，如果没有尚未发送的数据，就关闭EPOLLOUT
                    int sock_fd = ev[i].data.fd;
                    std::shared_ptr<CServerNode> node;
                    {
                        std::lock_guard<std::recursive_mutex> l(m_mutex_conn);
                        if (m_connections.find(sock_fd) == m_connections.end())
                            continue;
                        node = m_connections[sock_fd];
                        if (!node){
                            printf("EPOLLOUT | connections for fd %d is not valid.\n", sock_fd);
                            continue;
                        }
                    }
                    node->onSend();
                }
                else
                {
                    ;
                }
            }
        }
    }
}